
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>细节与最佳实践 - vue.js</title>
        <meta charset="utf-8">
        <meta name="description" content="Vue.js - Intuitive, Fast and Composable MVVM for building interactive interfaces.">
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
        <!-- <link href='http://fonts.googleapis.com/css?family=Source+Sans+Pro:400,600|Source+Code+Pro|Dosis:300,500' rel='stylesheet' type='text/css'> -->
        <link rel="icon" href="/images/logo.png" type="image/x-icon">
        <script>
            window.PAGE_TYPE = "教程"
        </script>
        <link rel="stylesheet" href="/css/page.css" type="text/css">
        <script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-46852172-1', 'vuejs.org');
  ga('send', 'pageview');
</script>
        <script src="/js/vue.js"></script>
    </head>
    <body>
        <div id="mobile-bar">
            <a class="menu-button"></a>
            <a class="logo" href="/"></a>
        </div>
        
            <div id="header">
    <a id="logo" href="/">
        <img src="/images/logo.png">
        <span>Vue.js</span>
    </a>
    <ul id="nav">
        <li>
  <form id="search-form">
    <input type="text" id="search-query" class="st-default-search-input">
  </form>
</li>
<li><a href="/guide/" class="nav-link current">教程</a></li>
<li><a href="/api/" class="nav-link">API</a></li>
<li><a href="/examples/" class="nav-link">示例</a></li>
<li><a href="/blog/" class="nav-link">Blog</a></li>
<li><a href="https://github.com/yyx990803/vue" target="_blank" class="nav-link">GitHub</a></li>

    </ul>
</div>
            <div id="main">
                
                    
    <div class="sidebar">
    <ul class="main-menu">
        <li>
  <form id="search-form">
    <input type="text" id="search-query" class="st-default-search-input">
  </form>
</li>
<li><a href="/guide/" class="nav-link current">教程</a></li>
<li><a href="/api/" class="nav-link">API</a></li>
<li><a href="/examples/" class="nav-link">示例</a></li>
<li><a href="/blog/" class="nav-link">Blog</a></li>
<li><a href="https://github.com/yyx990803/vue" target="_blank" class="nav-link">GitHub</a></li>

    </ul>
    <div class="list">
        <h2>教程</h2>
        <ul class="menu-root">
            
                <li>
                    <a href="/guide/installation.html" class="sidebar-link">安装</a>
                </li>
            
                <li>
                    <a href="/guide/index.html" class="sidebar-link">起步</a>
                </li>
            
                <li>
                    <a href="/guide/directives.html" class="sidebar-link">指令</a>
                </li>
            
                <li>
                    <a href="/guide/filters.html" class="sidebar-link">过滤器</a>
                </li>
            
                <li>
                    <a href="/guide/list.html" class="sidebar-link">列表渲染</a>
                </li>
            
                <li>
                    <a href="/guide/events.html" class="sidebar-link">事件监听</a>
                </li>
            
                <li>
                    <a href="/guide/forms.html" class="sidebar-link">处理表单</a>
                </li>
            
                <li>
                    <a href="/guide/computed.html" class="sidebar-link">计算属性</a>
                </li>
            
                <li>
                    <a href="/guide/custom-directive.html" class="sidebar-link">自定义指令</a>
                </li>
            
                <li>
                    <a href="/guide/custom-filter.html" class="sidebar-link">自定义过滤器</a>
                </li>
            
                <li>
                    <a href="/guide/components.html" class="sidebar-link">组件系统</a>
                </li>
            
                <li>
                    <a href="/guide/transitions.html" class="sidebar-link">过渡效果</a>
                </li>
            
                <li>
                    <a href="/guide/application.html" class="sidebar-link">创建大型应用</a>
                </li>
            
                <li>
                    <a href="/guide/extending.html" class="sidebar-link">扩展 Vue</a>
                </li>
            
                <li>
                    <a href="/guide/best-practices.html" class="sidebar-link current new">细节与最佳实践</a>
                </li>
            
                <li>
                    <a href="/guide/faq.html" class="sidebar-link">常见问题</a>
                </li>
            
            <li><a href="http://legacy.vuejs.org">旧版 0.11 文档</a></li>
            <li style="margin:10px 0 3px">
              <script data-gittip-username="yyx990803"
                data-gittip-widget="button"
                src="//gttp.co/v1.js"></script>
            </li>
        </ul>
    </div>
</div>


<div class="content 教程 with-sidebar">
    <h1>细节与最佳实践</h1>
    <div id="ad">
        <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?zoneid=1673&serve=C6AILKT&placement=vuejs" id="_carbonads_js"></script>
    </div>
    <h2 id="数据初始化">数据初始化</h2><p>明确定义的数据模型更加适合 Vue 的数据观察模式。建议在定义组件时，在 <code>data</code> 选项中初始化所有需要进行动态观察的属性。例如，给定下面的模版：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">div</span> <span class="attribute">id</span>=<span class="value">"demo"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">p</span> <span class="attribute">v-class</span>=<span class="value">"green: validation.valid"</span>&gt;</span>&#123;&#123;message&#125;&#125;<span class="tag">&lt;/<span class="title">p</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">input</span> <span class="attribute">v-model</span>=<span class="value">"message"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">div</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>建议像这样初始化你的数据，而不是什么都不定义：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> Vue(&#123;</span><br><span class="line">  el: <span class="string">'#demo'</span>,</span><br><span class="line">  data: &#123;</span><br><span class="line">    message: <span class="string">''</span>,</span><br><span class="line">    validation: &#123;</span><br><span class="line">      valid: <span class="literal">false</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<p>为什么要这样做呢？因为 Vue 是通过递归遍历初始数据中的所有属性，并用 <code>Object.defineProperty</code> 把它们转化为 getter 和 setter 来实现数据观察的。如果一个属性在实例创建时不存在于初始数据中，那么 Vue 就没有办法观察这个属性了。</p>
<p>当然，你也不需要对每一个可能存在的嵌套属性都进行初始定义。在初始化的时候可以将一个属性置为空对象，然后在后面的操作中设置为一个新的拥有嵌套结构的对象。只要这个新对象包含了应有的属性，Vue 依然能对这个新对象进行递归遍历，从而观察其内部属性。</p>
<h2 id="添加和删除属性">添加和删除属性</h2><p>正如前面所说的， Vue 会使用 <code>Object.defineProperty</code> 通过转化属性值来观察数据。不过，在 ECMAScript 5 中，当一个新的属性被添加到对象或者从对象中删除的时候，并没有办法可以检测到这两种情况。为了解决这个问题，Vue 会为被观察的对象添加三个扩展方法：</p>
<ul>
<li><code>obj.$add(key, value)</code></li>
<li><code>obj.$set(key, value)</code></li>
<li><code>obj.$delete(key)</code></li>
</ul>
<p>通过调用这些方法给观察对象中添加或者删除属性，就能够触发所对应的 DOM 更新。<code>$add</code> 和 <code>$set</code> 的区别是，假如当前对象已经含有所使用的 key， <code>$add</code> 会直接返回。所以当使用 <code>$obj.$add(key)</code> 的时候不会将已经存在的值覆盖为 <code>undefined</code>。</p>
<p>另外需要注意的一点是，当你通过数组索引赋值来改动数组时 (比如 <code>arr[1] = value</code>)，Vue 是无法侦测到这类操作的。类似地，你可以使用扩展方法来确保 Vue.js 收到了通知。被观察的数组有两个扩展方法：</p>
<ul>
<li><code>arr.$set(index, value)</code></li>
<li><code>arr.$remove(index | value)</code></li>
</ul>
<p>Vue 组件实例也有相应的实例方法：</p>
<ul>
<li><code>vm.$get(path)</code></li>
<li><code>vm.$set(path, value)</code></li>
<li><code>vm.$add(key, value)</code></li>
<li><code>vm.$delete(key, value)</code></li>
</ul>
<p>注意 <code>vm.$get</code> 和 <code>vm.$set</code> 都接受路径。</p>
<p class="tip">尽管存在这些方法，但我强烈建议你只在必要的时候才动态添加可观察属性。为了理解你的组件状态，将 <code>data</code> 选项看做一个 schema 很有帮助。假如你清晰地列出一个组件中所有可能存在的属性，那么当你隔了几个月再来维护这个组件的时候，就可以更容易地理解这个组件可能包含怎样的状态。</p>

<h2 id="理解异步更新">理解异步更新</h2><p>默认情况下， Vue 的 DOM 更新是<strong>异步执行</strong>的。理解这一点非常重要。当侦测到数据变化时， Vue 会打开一个队列，然后把在同一个事件循环 (event loop) 当中观察到数据变化的 watcher 推送进这个队列。假如一个 watcher 在一个事件循环中被触发了多次，它只会被推送到队列中一次。然后，在进入下一次的事件循环时， Vue 会清空队列并进行必要的 DOM 更新。在内部，Vue 会使用 <code>MutationObserver</code> 来实现队列的异步处理，如果不支持则会回退到 <code>setTimeout(fn, 0)</code>。</p>
<p>举例来说，当你设置 <code>vm.someData = &#39;new value&#39;</code>，DOM 并不会马上更新，而是在异步队列被清除，也就是下一个事件循环开始时执行更新。如果你想要根据更新的 DOM 状态去做某些事情，就必须要留意这个细节。尽管 Vue.js 鼓励开发者用 “数据驱动” 的方式想问题，避免直接操作 DOM ，但有时候你可能就是想要使用某个熟悉的 jQuery 插件。这种情况下怎么办呢？你可以在数据改变后，立刻调用 <code>Vue.nextTick(callback)</code>，并把你要做的事情放到回调函数里面。当 <code>Vue.nextTick</code> 的回调函数执行时，DOM 将会已经是更新后的状态了。</p>
<p>示例：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">div</span> <span class="attribute">id</span>=<span class="value">"example"</span>&gt;</span>&#123;&#123;msg&#125;&#125;<span class="tag">&lt;/<span class="title">div</span>&gt;</span></span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> vm = <span class="keyword">new</span> Vue(&#123;</span><br><span class="line">  el: <span class="string">'#example'</span>,</span><br><span class="line">  data: &#123;</span><br><span class="line">    msg: <span class="string">'123'</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line">vm.msg = <span class="string">'new message'</span> <span class="comment">// change data</span></span><br><span class="line">vm.$el.textContent === <span class="string">'new message'</span> <span class="comment">// false</span></span><br><span class="line">Vue.nextTick(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  vm.$el.textContent === <span class="string">'new message'</span> <span class="comment">// true</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<p>除此之外，也有一个实例方法 <code>vm.$nextTick()</code>。这个方法和全局的 <code>Vue.nextTick</code> 功能一样，但更方便在组件内部使用，因为它不需要全局的 <code>Vue</code> 变量，另外它的回调函数的 <code>this</code> 上下文会自动绑定到调用它的 Vue 实例：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">Vue.component(<span class="string">'example'</span>, &#123;</span><br><span class="line">  template: <span class="string">'&lt;span&gt;&#123;&#123;msg&#125;&#125;&lt;/span&gt;'</span>,</span><br><span class="line">  data: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      msg: <span class="string">'not updated'</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    updateMessage: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">      <span class="keyword">this</span>.msg = <span class="string">'updated'</span></span><br><span class="line">      <span class="built_in">console</span>.log(<span class="keyword">this</span>.$el.textContent) <span class="comment">// =&gt; 'not updated'</span></span><br><span class="line">      <span class="keyword">this</span>.$nextTick(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="keyword">this</span>.$el.textContent) <span class="comment">// =&gt; 'updated'</span></span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<h2 id="组件作用域">组件作用域</h2><p>每一个 Vue.js 组件都是一个拥有自己的独立作用域的 Vue 实例。在使用组件的时候，理解组件作用域机制非常重要。其规则概括来说就是：</p>
<blockquote>
<p>在父模板中出现的，将在父模板作用域内编译；在子模板中出现的，将在子模板的作用域内编译。</p>
</blockquote>
<p>一个常见的错误是，在父模版中尝试将一个指令绑定到子作用域里的属性或者方法上：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">div</span> <span class="attribute">id</span>=<span class="value">"demo"</span>&gt;</span></span><br><span class="line">  <span class="comment">&lt;!-- 不起作用，因为作用域不对！ --&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">child-component</span> <span class="attribute">v-on</span>=<span class="value">"click: childMethod"</span>&gt;</span><span class="tag">&lt;/<span class="title">child-component</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">div</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>如果需要在子组件的根节点上绑定指令，应当将指令写在子组件的模板内：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">Vue.component(<span class="string">'child-component'</span>, &#123;</span><br><span class="line">  <span class="comment">// 这次作用域对了</span></span><br><span class="line">  template: <span class="string">'&lt;div v-on="click: childMethod"&gt;Child&lt;/div&gt;'</span>,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    childMethod: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'child method invoked!'</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<p>注意，当组件和 <code>v-repeat</code> 一同使用时，<code>$index</code> 作为子作用域属性也会受到此规则的影响。</p>
<p>另外，父模板里组件节点内部的 HTML 内容被看做是 “transclusion content”（插入内容）。除非子模版包含至少一个 <code>&lt;content&gt;</code>出口，不然这些插入内容不会被渲染。需要留意的是，插入内容也是<strong>在父作用域中编译</strong>的：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">div</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">child-component</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 在父作用域里编译 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">p</span>&gt;</span>&#123;&#123;msg&#125;&#125;<span class="tag">&lt;/<span class="title">p</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="title">child-component</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">div</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>你可以使用 <code>inline-template</code> 属性去明确内容在子模版的作用域中被编译：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">div</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">child-component</span> <span class="attribute">inline-template</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 在子作用域里编译 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">p</span>&gt;</span>&#123;&#123;msg&#125;&#125;<span class="tag">&lt;/<span class="title">p</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="title">child-component</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">div</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>更多关于内容插入的细节，请看组件一章的 <a href="/guide/components.html#内容插入">内容插入</a> 小节。</p>
<h2 id="在多个实例之间通讯">在多个实例之间通讯</h2><p>一种常见的在 Vue 中进行父子通讯的方法是，通过 <code>props</code> 传递一个父方法作为一个回调到子组件中。这样使用时的回调传递可以被定义在父模版中，从而保持了组件之间 Javascript 实现细节上的解耦：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">div</span> <span class="attribute">id</span>=<span class="value">"demo"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">p</span>&gt;</span>Child says: &#123;&#123;msg&#125;&#125;<span class="tag">&lt;/<span class="title">p</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">child-component</span> <span class="attribute">send-message</span>=<span class="value">"&#123;&#123;onChildMsg&#125;&#125;"</span>&gt;</span><span class="tag">&lt;/<span class="title">child-component</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">div</span>&gt;</span></span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> Vue(&#123;</span><br><span class="line">  el: <span class="string">'#demo'</span>,</span><br><span class="line">  data: &#123;</span><br><span class="line">    msg: <span class="string">''</span></span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    onChildMsg: <span class="function"><span class="keyword">function</span>(<span class="params">msg</span>) </span>&#123;</span><br><span class="line">      <span class="keyword">this</span>.msg = msg</span><br><span class="line">      <span class="keyword">return</span> <span class="string">'Got it!'</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  components: &#123;</span><br><span class="line">    <span class="string">'child-component'</span>: &#123;</span><br><span class="line">      props: [</span><br><span class="line">        <span class="comment">// you can use prop assertions to ensure the</span></span><br><span class="line">        <span class="comment">// callback prop is indeed a function.</span></span><br><span class="line">        &#123;</span><br><span class="line">          name: <span class="string">'send-message'</span>,</span><br><span class="line">          type: <span class="built_in">Function</span>,</span><br><span class="line">          required: <span class="literal">true</span></span><br><span class="line">        &#125;</span><br><span class="line">      ],</span><br><span class="line">      <span class="comment">// props with hyphens are auto-camelized</span></span><br><span class="line">      template:</span><br><span class="line">        <span class="string">'&lt;button v-on="click:onClick"&gt;Say Yeah!&lt;/button&gt;'</span> +</span><br><span class="line">        <span class="string">'&lt;p&gt;Parent responds: &#123;&#123;response&#125;&#125;&lt;/p&gt;'</span>,</span><br><span class="line">      <span class="comment">// component `data` option must be a function</span></span><br><span class="line">      data: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> &#123;</span><br><span class="line">          response: <span class="string">''</span></span><br><span class="line">        &#125;</span><br><span class="line">      &#125;,</span><br><span class="line">      methods: &#123;</span><br><span class="line">        onClick: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">          <span class="keyword">this</span>.response = <span class="keyword">this</span>.sendMessage(<span class="string">'Yeah!'</span>)</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<p><strong>Result:</strong></p>
<div id="demo"><p>Child says: {&#123;msg&#125;}</p><child-component send-message="{&#123;onChildMsg&#125;}"></child-component></div>

<script>
new Vue({
  el: '#demo',
  data: {
    msg: ''
  },
  methods: {
    onChildMsg: function(msg) {
      this.msg = msg
      return 'Got it!'
    }
  },
  components: {
    'child-component': {
      props: ['send-message'],
      data: function () {
        return {
          fromParent: ''
        }
      },
      template:
        '<button v-on="click:onClick">Say Yeah!</button>' +
        '<p>Parent responds: <span v-text="fromParent"></span></p>',
      methods: {
        onClick: function () {
          this.fromParent = this.sendMessage('Yeah!')
        }
      }
    }
  }
})
</script>

<p>当你需要跨越多层嵌套的组件进行通讯时，你可以使用<a href="/api/instance-methods.html#事件系统">事件系统</a> 。另外，在构建大型应用时，用 Vue 搭配类似 <a href="https://facebook.github.io/flux/docs/overview.html" target="_blank" rel="external">Flux</a> 的架构也是完全可行的。</p>
<h2 id="片段实例">片段实例</h2><p>自 0.12.2 起，replace 参数默认为 true。这意味着：</p>
<blockquote>
<p>组件的模板长什么样，渲染出来的 DOM 就是什么样。</p>
</blockquote>
<p>父模板中调用组件的元素将会被组件本身的模板取代。因此，如果组件的模板包含多个顶级元素：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Vue.component(<span class="string">'example'</span>, &#123;</span><br><span class="line">  template:</span><br><span class="line">    <span class="string">'&lt;div&gt;A&lt;/div&gt;'</span> +</span><br><span class="line">    <span class="string">'&lt;div&gt;B&lt;/div&gt;'</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<p>或者模板只包含文本：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Vue.component(<span class="string">'example'</span>, &#123;</span><br><span class="line">  template: <span class="string">'Hello world'</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<p>在这两个情况下，实例将变成一个<strong>片段实例</strong> (fragment instance)，也即没有根元素的实例。它的 $el 指向一个锚节点（普通模式下是空的文本节点，debug 模式下是注释节点）。更重要的是，父模板组件元素上的指令、过渡效果和属性绑定（props 除外）将无效，因为生成的实例并没有根元素供它们绑定：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- 指令不生效，因为没有根元素用来绑定 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">example</span> <span class="attribute">v-show</span>=<span class="value">"ok"</span> <span class="attribute">v-transition</span>=<span class="value">"fade"</span>&gt;</span><span class="tag">&lt;/<span class="title">example</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&lt;!-- props 还是能够正常生效 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">example</span> <span class="attribute">prop</span>=<span class="value">"&#123;&#123;someData&#125;&#125;"</span>&gt;</span><span class="tag">&lt;/<span class="title">example</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>虽然片段实例也有其使用场景，但是大部分情况下，给组件模板一个根元素是推荐的做法。这样父模板组件元素上的指令和属性能正常运转，并且性能也会更好一点。</p>
<h2 id="修改默认选项">修改默认选项</h2><p>通过修改全局的 <code>Vue.options</code> 对象，可以修改实例选项的默认值。例如，你可以设置 <code>Vue.options.replace = false</code> ，使所有 Vue 实例都按照 <code>replace: false</code> 的规则被编译。请谨慎使用这个功能 - 最好是只在一个项目刚开始的时候使用它，因为它会影响所有 Vue 实例的行为。</p>
<p>下一节：<a href="/guide/faq.html">常见问题</a>.</p>

    <div class="footer">发现了问题或想要贡献？来 Github 给 Vue.js <a href="https://github.com/vuejs/vuejs.org" target="_blank">英文站点</a>或<a href="https://github.com/Jinjiang/vuejs.org/tree/lang-zh" target="_blank">中文翻译</a>来个 Fork 吧！</div>
</div>
                
            </div>
            <script src="/js/smooth-scroll.min.js"></script>
            <script src="/js/common.js"></script>
        

        <script src="https://cdnjs.cloudflare.com/ajax/libs/fastclick/1.0.6/fastclick.min.js"></script><script src="https://cdn.jsdelivr.net/gh/shentao/vuejs-outdated-docs-modal@v1.3/prompt.min.js"></script>
        <script>
            document.addEventListener('DOMContentLoaded', function() {
                FastClick.attach(document.body);
            }, false);
        </script>
    </body>
</html>
